//! @Author: DengLibin
//! @Date: Create in 2024-07-18 13:59:59
//! @Description: 自定义宏

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Field, Fields, ItemStruct, LitStr};



/// @Author: DengLibin
/// @Date: Create in 2024-07-18 13:58:20
/// @Description: 获取结构体字段名
#[proc_macro_derive(GetFieldNames)]
pub fn get_field_names_macro(input: TokenStream) -> TokenStream {
    // 解析输入的 Rust 代码
    let input = parse_macro_input!(input as DeriveInput);
    
    // 获取结构体名称和字段信息
    let struct_name = &input.ident;
    let field_names = if let syn::Data::Struct(ref data_struct) = input.data {
        if let syn::Fields::Named(ref fields) = data_struct.fields {
            fields
                .named
                .iter()
                .map(|f| f.ident.as_ref().unwrap().to_string())
                .collect::<Vec<_>>()
        } else {
            vec![]
        }
    } else {
        vec![]
    };

    // 生成代码，返回字段名的 Vec<String>
    let output = quote! {
        impl #struct_name {
            pub fn get_field_names() -> Vec<String> {
                vec![
                    #(
                        String::from(#field_names),
                    )*
                ]
            }
        }
    };

    // 将生成的代码作为 TokenStream 返回
    output.into()
}




/// @Author: DengLibin
/// @Date: Create in 2024-07-18 14:10:35
/// @Description: 结构体转map

#[proc_macro_derive(MyStructToMap)]
pub fn struct_to_map_macro(input: TokenStream) -> TokenStream {
    // 解析输入的 Rust 代码
    let input = parse_macro_input!(input as DeriveInput);
    let struct_name = &input.ident;

    // 获取结构体字段信息，并生成转换为 HashMap 的代码
    let (field_names, _field_types) = if let syn::Data::Struct(ref data_struct) = input.data {
        if let syn::Fields::Named(ref fields) = data_struct.fields {
            let names = fields.named.iter().map(|f| {
                let name = f.ident.as_ref().unwrap();
                let field_name = name.to_string();
                quote! {
                    map.insert(String::from(#field_name), serde_json::to_value(&self.#name).unwrap());
                }
            });
            (names.collect::<Vec<_>>(), quote! {})
        } else {
            (vec![], quote! {})
        }
    } else {
        (vec![], quote! {})
    };

    // 生成代码，实现 StructToMap trait
    let output = quote! {
        impl #struct_name {
            pub fn to_map(&self) -> std::collections::HashMap<String, serde_json::Value> {
                let mut map = std::collections::HashMap::new();
                #(#field_names)*
                map
            }
        }
    };

    // 将生成的代码作为 TokenStream 返回
    output.into()
}



/// @Author: DengLibin
/// @Date: Create in 2024-07-18 15:52:04
/// @Description: 加了这个宏,自动实现 my_trait::MustHaveTableName 这个trait
#[proc_macro_attribute]
pub fn table_name(attr: TokenStream, item: TokenStream) -> TokenStream {
    // 解析属性值
    let table_name = parse_macro_input!(attr as LitStr).value();

    // 解析输入的 Rust 代码
    let input = parse_macro_input!(item as ItemStruct);

    // 获取结构体名称和类型参数
    let struct_name = &input.ident;
    let generics = &input.generics;

    // 生成代码，为结构体添加一个名为 table_name 的方法，返回设置的属性值
    // 并实现 MustHaveTableName trait
    let output = quote! {
        #input

        impl #generics MustHaveTableName for #struct_name #generics {
            fn table_name() -> &'static str {
                #table_name
            }
        }
    };

    // 将生成的代码作为 TokenStream 返回
    output.into()
}

/// @Author: DengLibin
/// @Date: Create in 2024-07-19 15:06:41
/// @Description: 获取字段类型 实现 my_trait:MustHaveFieldType
#[proc_macro_derive(HaveFieldType)]
pub fn must_have_field_type_derive(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as DeriveInput);
    let name = &input.ident;

    let field_types_map = match &input.data {
        Data::Struct(data_struct) => match &data_struct.fields {
            Fields::Named(fields) => {
                let fields = fields.named.iter().map(|field: &Field| {
                    let field_name = field.ident.as_ref().unwrap();
                    let field_type = &field.ty;
                    quote! {
                        map.insert(
                            stringify!(#field_name).to_string(),
                            stringify!(#field_type).to_string().replace(" ", ""),
                        );
                    }
                });
                quote! {
                    let mut map = std::collections::HashMap::new();
                    #(#fields)*
                    map
                }
            }
            _ => {
                panic!("MustHaveFieldType can only be derived for structs with named fields");
            }
        },
        _ => {
            panic!("MustHaveFieldType can only be derived for structs");
        }
    };

    let expanded = quote! {
        impl MustHaveFieldType for #name {
            fn field_types_map() -> std::collections::HashMap<String, String> {
                #field_types_map
            }
        }
    };

    TokenStream::from(expanded)
}


/// @Author: DengLibin
/// @Date: Create in 2024-07-19 15:05:32
/// @Description: 结构体转map 并实现my_trait::Struct2Map这个trait
#[proc_macro_derive(StructToMap)]
pub fn struct_to_map_derive(input: TokenStream) -> TokenStream {
    // 解析输入的 Rust 代码
    let input = parse_macro_input!(input as DeriveInput);

    // 获取结构体的名称
    let name = &input.ident;

    // 处理结构体的数据
    let expanded = if let syn::Data::Struct(data_struct) = input.data {
        let fields = if let syn::Fields::Named(fields_named) = data_struct.fields {
            fields_named
        } else {
            panic!("StructToMap can only be derived for structs with named fields");
        };

        let field_names = fields.named.iter().map(|field| &field.ident);
        let field_names_str = fields.named.iter().map(|field| field.ident.as_ref().unwrap().to_string());

        quote! {
            impl Struct2Map for #name {
                fn to_map(&self) -> ::std::collections::HashMap<String, ::serde_json::Value> {
                    let mut map = ::std::collections::HashMap::new();
                    #( map.insert(#field_names_str.to_string(), ::serde_json::json!(self.#field_names)); )*
                    map
                }
            }
        }
    } else {
        panic!("StructToMap can only be derived for structs");
    };

    // 将生成的代码转换为 TokenStream
    TokenStream::from(expanded)
}